package com.bigcat.gulimall.demo.logs.service;

import com.aliyun.openservices.log.Client;
import com.aliyun.openservices.log.common.LogContent;
import com.aliyun.openservices.log.exception.LogException;
import com.aliyun.openservices.log.response.GetLogsResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 阿里云日志获取
 */
@Service
@Slf4j
public class AliyunLogServiceImpl {

    @Autowired
    Client aliyunLogClient;

    @Value("${aliyun.logsServer.queryHistoryLocationsLog}")
    private String queryHistoryLocationsLog;
    @Value("${aliyun.logsServer.countHistoryLocationsLog}")
    private String countHistoryLocationsLog;
    @Value("${aliyun.logsServer.queryHistoryStatusLog}")
    private String queryHistoryStatusLog;
    @Value("${aliyun.logsServer.countHistoryStatusLog}")
    private String countHistoryStatusLog;

    @Value("${aliyun.logsServer.queryDeviceHeartBeatLoc}")
    private String queryDeviceHeartBeatLoc;

    @Value("${aliyun.logsServer.project}")
    private String project;
    @Value("${aliyun.logsServer.logStore}")
    private String logStore;



    /**
     * 分页查询设备某段时间状态日志
     * @param deviceId 设备编号
     * @param from  开始时间
     * @param to    结束时间
     * @param page  页码
     * @param pageSize  每页大小
     */
    public List<Map<String, String>> getHistoryStatusLog(String deviceId, LocalDateTime from, LocalDateTime to, int page, int pageSize) {
        Assert.notNull(from, "开始时间不能为空");
        Assert.notNull(to, "结束时间不能为空");
        if (0 >= page) {
            page = 1;
        }
        String queryStr = String.format(queryHistoryStatusLog, deviceId);
        Assert.hasText(queryStr, "查询语句不能为空");
        queryStr += " limit " + (pageSize * (page - 1)) + "," + pageSize;
        return getLogs(from, to, queryStr);
    }

    /**
     * 统计设备某段时间状态日志
     *
     * @param deviceId 设备编号
     * @param from     开始时间
     * @param to       结束时间
     * @return 日志原始数据
     */
    public int countHistoryStatusLog(String deviceId, LocalDateTime from, LocalDateTime to) {
        Assert.notNull(from, "开始时间不能为空");
        Assert.notNull(to, "结束时间不能为空");
        String queryStr = String.format(countHistoryStatusLog, deviceId);
        Assert.hasText(queryStr, "查询语句不能为空");

        return getCount(queryStr, from, to);
    }

    /**
     * 查询某时间段所有设备位置日志
     *
     * @param deviceId 设备编号
     * @param from     开始时间
     * @param to       结束时间
     * @return MAP
     */
    public List<Map<String, String>> getHistorySCoordinateLog(String deviceId, LocalDateTime from, LocalDateTime to, int page, int pageSize) {
        if (0 >= page) {
            page = 1;
        }
        Assert.notNull(from, "开始时间不能为空");
        Assert.notNull(to, "结束时间不能为空");
        String queryStr = String.format(queryHistoryLocationsLog, deviceId);
        Assert.hasText(queryStr, "查询语句不能为空");
        queryStr += " limit " + (pageSize * (page - 1)) + "," + pageSize;
        return getLogs(from, to, queryStr);
    }

    /**
     * 统计某时间段所有设备位置日志
     *
     * @param deviceId 设备编号
     * @param from     开始时间
     * @param to       结束时间
     * @return 日志原始数据
     */
    public int countHistoryCoordinateLog(String deviceId, LocalDateTime from, LocalDateTime to) {
        Assert.notNull(from, "开始时间不能为空");
        Assert.notNull(to, "结束时间不能为空");
        String queryStr = String.format(countHistoryLocationsLog, deviceId);
        Assert.hasText(queryStr, "查询语句不能为空");

        return getCount(queryStr, from, to);
    }

    /**
     * 返回原始数据
     *
     * @param deviceId 设备编号
     * @param from     开始时间
     * @param to       结束时间
     * @return 日志原始数据
     */
    public int GetLogResponse(String deviceId, LocalDateTime from, LocalDateTime to) {
        Assert.notNull(from, "开始时间不能为空");
        Assert.notNull(to, "结束时间不能为空");
        String queryStr = String.format(countHistoryStatusLog, deviceId);
        Assert.hasText(queryStr, "查询语句不能为空");

        return getCount(queryStr, from, to);
    }

    /**
     *  查询某时间段所有日志
     * @param from 开始时间
     * @param to 结束时间
     * @param query 查询语句
     */
    private List<Map<String, String>> getLogs(LocalDateTime from, LocalDateTime to, String query) {
        Assert.notNull(from, "开始时间不能为空");
        Assert.notNull(to, "结束时间不能为空");
        log.debug("日志查询 -> 查询语句:{}", query);

        GetLogsResponse logsResponse = getLogsResponse(from, to, query);
        Assert.notNull(logsResponse, "日志服务返回数据为NULL");

        List<Map<String, String>> logs = new ArrayList<>();
        logsResponse.GetLogs().forEach(queriedLog -> logs.add(queriedLog.mLogItem.mContents.stream().
            collect(Collectors.toMap(LogContent::GetKey, LogContent::GetValue))));
        return logs;
    }

    /**
     * 统计日志总数
     * @param queryStr 查询语句
     * @param from     开始时间
     * @param to       结束时间
     * @return 统计日志总数
     */
    private int getCount(String queryStr, LocalDateTime from, LocalDateTime to) {

        GetLogsResponse getLogsResponse = getLogsResponse(from, to, queryStr);

        if (null == getLogsResponse || null == getLogsResponse.GetLogs() || getLogsResponse.GetLogs().size() <= 0) {
            return 0;
        }
        return Integer.parseInt(getLogsResponse.GetLogs().get(0).mLogItem.mContents.get(0).mValue);
    }

    /**
     * @param queryStr 查询语句
     * @param from     开始时间
     * @param to       结束时间
     * @return 统计日志总数
     */
    private GetLogsResponse getLogsResponse(LocalDateTime from, LocalDateTime to, String queryStr) {

        int fromValue;
        int toValue;

        fromValue = (int) from.toEpochSecond(ZoneOffset.of("+8"));
        toValue = (int) to.toEpochSecond(ZoneOffset.of("+8"));

        GetLogsResponse getLogsResponse;
        try {
            getLogsResponse = aliyunLogClient.GetLogs(project, logStore, fromValue, toValue, "", queryStr, 0, 0, false);
        } catch (LogException l) {
            log.error("日志查询异常:{}", l.getMessage());
            return null;
        }
        return getLogsResponse;
    }

    /**
     * 获得设备心跳定位信息
     *
     * @param deviceId
     * @param from
     * @param to
     * @param page
     * @param pageSize
     * @return
     */
    public List<Map<String, String>> getDeviceHeatBeatLocList(String deviceId, LocalDateTime from, LocalDateTime to, int page, int pageSize) {
        String queryStr = String.format(queryDeviceHeartBeatLoc, deviceId);
        if (StringUtils.isEmpty(queryStr)) {
            log.info("查询语句不能为空");
            return null;
        }
        queryStr += " limit " + (pageSize * (page - 1)) + "," + pageSize;
        return getLogs(from, to, queryStr);
    }

    public List<Map<String, String>> queryMacInfoByMac(LocalDateTime beginTime, LocalDateTime endTime, String mac) {
        String queryStr = "_container_name_:iot-protobuf and content:\"统一控制指令上送消息 --> response\" and content:\"%s\" | select regexp_extract(content,'deviceId:[A-Za-z0-9]+') as mac limit 1";
        String sql = String.format(queryStr, mac);
        if (StringUtils.isEmpty(queryStr)) {
            log.info("查询语句不能为空");
            return null;
        }
        return getLogs(beginTime, endTime, sql);
    }
}
